#ifndef TANKGAME_CALCULATION_H_
#define TANKGAME_CALCULATION_H_

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <cstring>
#include <string>
#include "json.hpp"
using nlohmann::json;

typedef std::pair<int,int> P;

typedef long long ll;
const int inf = 0x3f3f3f3f;
const int trans[5][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}, {0, 0}};
namespace CMInterfaceStruct {
#pragma pack(push, 1)
// map
struct Map {
    int width;
    int height;
    std::vector<std::vector<int>> coordinate_type;
};

// tank
struct Tank {
    int atk;
    int def;
    int height;
    int hp;
    std::string moving_direct;
    std::string tank_id;
    int width;
    int x;
    int y;
};

// bullet
struct Bullet {
    std::string bullet_id;
    int height;
    std::string moving_direct;
    std::string tank_id;
    int width;
    int x;
    int y;
};

// prop
struct Prop {
    int height;
    std::string prop_type_enums;
    int width;
    int x;
    int y;
};

// safe area
struct SafeArea {
    int left_time;
    int r;
    int x;
    int y;
};

// action
struct Action{
    // trans 0 1 2 3 4
    int moving_direct;
    bool fire;
};
#pragma pack(pop)
};

class Unit {
public:
    P point;
    int width;
    int height;
};

class Calculation {
public:
    static Calculation& GetInstance();
    bool Initialize(std::string main_tank_id_);
    CMInterfaceStruct::Action Move(
        const CMInterfaceStruct::Map& m, 
        const std::vector<CMInterfaceStruct::Tank> &tank_list,
        const std::vector<CMInterfaceStruct::Bullet> &bullet_list,
        const std::vector<CMInterfaceStruct::Prop> &prop_list,
        const CMInterfaceStruct::SafeArea &safe_area
    );
    CMInterfaceStruct::Action Move(const std::string &str);

    void Print();
private:
    Calculation();
    ~Calculation();

    Calculation(const Calculation &ca);
    const Calculation &operator=(const Calculation &ca);
private:
    // in map. return the min distance from A to B. and input A&B square length.
    int BreathFirstSearch(const CMInterfaceStruct::Map &mp, const Unit &A , const Unit &B);
    // find the min distance. we can attack the other tank. return the direction and distance.
    P EnemyDist(const CMInterfaceStruct::Map &mp, const CMInterfaceStruct::Tank &A , const CMInterfaceStruct::Tank &B);
    // return the results of judgement. which action to choose.
    // can't avoid if return 0.
    // can offset if return 1.
    // can avoid if return 2.
    // can offset and avoid return 3.
    int BulletSolve(const CMInterfaceStruct::Map &mp, const CMInterfaceStruct::Tank &A , const CMInterfaceStruct::Bullet &B);
    // return weight table.
    std::vector<int> DangerousBullets(const CMInterfaceStruct::Map &mp, const CMInterfaceStruct::Tank &A, const std::vector<CMInterfaceStruct::Bullet> &bullets);
    // return point weight.
    int WayToGo(const CMInterfaceStruct::Map &mp, const P &A);
    // return weight table.
    std::vector<int> BestProp(const CMInterfaceStruct::Map &mp, const CMInterfaceStruct::Tank &A, const std::vector<CMInterfaceStruct::Tank> &enemys, const std::vector<CMInterfaceStruct::Prop> &props);
    // return true if out of ring
    bool OutRing(const CMInterfaceStruct::SafeArea &area, const P &A);
    // return if we can't attank to the other tank.
    bool EnemyStrong(const CMInterfaceStruct::Tank &A, const CMInterfaceStruct::Tank &B);
    // return weight table.
    std::vector<int> BestChoiceOfRing(const CMInterfaceStruct::Map &mp, const CMInterfaceStruct::Tank &B, const std::vector<CMInterfaceStruct::Tank> &enemys, const CMInterfaceStruct::SafeArea &area);
    // return action. 
    CMInterfaceStruct::Action FireLogic(const CMInterfaceStruct::Map &mp,  const CMInterfaceStruct::Tank &B, const std::vector<CMInterfaceStruct::Tank> &enemys);
    // return weight table.
    std::vector<int> FirePrepare(const CMInterfaceStruct::Map &mp, const CMInterfaceStruct::Tank &B, const std::vector<CMInterfaceStruct::Tank> &enemys);
private:
    std::string main_tank_id_;
};

#endif